import type { Metadata } from 'next'; import { notFound, permanentRedirect } from 'next/navigation'; import { describeModel, ModelPage, type ModelPageParams } from '@/components/entity/model-page'; import { api, ApiError, apiD1, safe } from '@/lib/api'; import { routes, SITE_NAME, SITE_URL } from '@/lib/site'; import type { ModelDetail } from '@/lib/types'; type Params = { params: Promise<{ slug: string }>; searchParams: Promise }; /** `/models/` accepts models AND artifacts, and resolves folded variants to their canonical model (`redirected_from`). */ export async function loadModelOrArtifact(slug: string): Promise { try { return await apiD1.model(slug); } catch (e) { if (e instanceof ApiError && e.notFound) notFound(); throw e; } } export async function generateMetadata({ params }: Params): Promise { const { slug } = await params; const d = await safe(apiD1.model(slug)); if (!d || d.entity_type === 'artifact' || d.slug !== slug) return { title: 'Model', robots: { index: false } }; const title = `${d.name} — Parameters, Context, Benchmarks & Pricing`; const description = describeModel(d); const canonical = routes.entity(d); return { title, description, alternates: { canonical }, openGraph: { title: `${title} | ${SITE_NAME}`, description, url: `${SITE_URL}${canonical}`, type: 'article', siteName: SITE_NAME }, twitter: { card: 'summary_large_image', title, description }, }; } export default async function ModelRoute({ params, searchParams }: Params) { const { slug } = await params; const sp = await searchParams; const d = await loadModelOrArtifact(slug); // Old URLs keep resolving: artifacts live at /artifacts/; folded evaluation variants and aliases 308 to the canonical model. if (d.entity_type === 'artifact') permanentRedirect(routes.artifact(d.slug)); if (d.redirected_from || d.slug !== slug) permanentRedirect(routes.entity(d)); if (d.entity_type !== 'model' && d.entity_type !== 'quantization') notFound(); const related = await safe(api.entityRelated(d.slug, 10)); return ; }